/**
* MComboBoxModel - A ComboBoxModel for use with an MComboBox
*
* Copyright (c) 2002
* Marty Phelan, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package com.taursys.swing;
import javax.swing.ComboBoxModel;
import javax.swing.AbstractListModel;
import javax.swing.event.*;
import java.util.*;
import com.taursys.model.*;
import com.taursys.model.event.*;
/**
* MComboBoxModel is a ComboBoxModel for use with an MComboBox.
* @author Marty Phelan
* @version 2.0
*/
public class MComboBoxModel extends AbstractListModel
implements ComboBoxModel {
private com.taursys.model.ListValueHolder listValueHolder;
transient private Vector listDataListeners;
private com.taursys.model.ValueHolder valueHolder;
private String[] propertyNames = new String[] {"value"};
private String[] listPropertyNames = new String[] {"value"};
private ListChangeListener listChangeListener =
new ListChangeListener();
private ValueHolderChangeListener valueHolderChangeListener =
new ValueHolderChangeListener();
private boolean settingSelection = false;
private boolean nullAllowed = false;
private String nullDisplay = "--none--";
private NullObject nullObject = new NullObject();
private Object selectedItem = null;
transient private Vector enableListeners;
// *************************************************************************
// Constructors
// *************************************************************************
/**
* Constructs a new model with an empty option list.
*/
public MComboBoxModel() {
setListValueHolder(new ObjectListValueHolder());
setValueHolder(new ObjectValueHolder());
}
/**
* Constructs a new model with the given items as the option list.
*/
public MComboBoxModel(Object[] items) {
if (items != null) {
setListValueHolder(new ObjectListValueHolder(
new ArrayList(Arrays.asList(items))));
} else {
setListValueHolder(new ObjectListValueHolder());
}
setValueHolder(new ObjectValueHolder());
}
// *************************************************************************
// Selection Methods
// *************************************************************************
/**
* Set the selected item in the list.
* @param anItem the selected item in the list.
*/
public void setSelectedItem(Object anItem) {
try {
settingSelection = true;
if (anItem instanceof NullObject) {
Object[] values = new Object[listPropertyNames.length];
// next
valueHolder.setPropertyValues(
propertyNames, values);
this.selectedItem = anItem;
} else {
// get index of selection
int index = listValueHolder.indexOf(anItem);
if (index > -1) {
Object[] values = listValueHolder.getPropertyValues(
listPropertyNames, index);
valueHolder.setPropertyValues(
propertyNames, values);
this.selectedItem = anItem;
}
}
} catch (Exception ex) {
com.taursys.debug.Debug.debug("Error during setSelectedItem", ex);
} finally {
settingSelection = false;
}
}
/**
* Get the selected item in the list.
* @return the selected item in the list.
*/
public Object getSelectedItem() {
return selectedItem;
}
/**
* Get the current size of the list.
* @return the current size of the list.
*/
public int getSize() {
if (listValueHolder == null)
return 0;
else
if (isNullAllowed())
return listValueHolder.getRowCount() + 1;
else
return listValueHolder.getRowCount();
}
/**
* Get the item from the list at the given index.
* @param index indicates which item to return.
* @return the item from the list at the given index.
*/
public Object getElementAt(int index) {
if (listValueHolder == null)
return null;
else
if (isNullAllowed())
if (index == 0) {
return nullObject;
} else {
return listValueHolder.get(index - 1);
}
else
return listValueHolder.get(index);
}
// =======================================================================
// ValueHolder Properties
// =======================================================================
/**
* Set the ValueHolder which will store the selection
* @param valueHolder the ValueHolder which will store the selection
*/
public void setValueHolder(ValueHolder valueHolder) {
if (valueHolder != null)
valueHolder.removeChangeListener(valueHolderChangeListener);
this.valueHolder = valueHolder;
if (valueHolder != null)
valueHolder.addChangeListener(valueHolderChangeListener);
fireEnableChange(
new EnableEvent(this, isChangeable()));
}
/**
* Get the ValueHolder which will store the selection
* @return the ValueHolder which will store the selection
*/
public ValueHolder getValueHolder() {
return valueHolder;
}
/**
* Set the property name in the ValueHolder which will store the selection.
* This name must correspond with the listPropertyName.
* @param propertyName the property name in the ValueHolder which will store the selection.
*/
public void setPropertyName(String propertyName) {
if (propertyNames == null || propertyNames.length < 1)
propertyNames = new String[] {propertyName};
else
propertyNames[0] = propertyName;
}
/**
* Get the property name in the ValueHolder which will store the selection.
* This name must correspond with the listPropertyName.
* @return the property name in the ValueHolder which will store the selection.
*/
public String getPropertyName() {
if (propertyNames == null || propertyNames.length < 1)
return null;
else
return propertyNames[0];
}
/**
* Set the property names in the ValueHolder which will store the selection.
* The selection can be associated with multiple properties in the value holder.
* These property names must correspond to the listPropertyNames.
* @param propertyNames the property names in the ValueHolder which will store the selection.
*/
public void setPropertyNames(String[] propertyNames) {
propertyNames = propertyNames;
}
/**
* Get the property names in the ValueHolder which will store the selection.
* The selection can be associated with multiple properties in the value holder.
* These property names must correspond to the listPropertyNames.
* @return the property names in the ValueHolder which will store the selection.
*/
public String[] getPropertyNames() {
return propertyNames;
}
/**
* Invoked whenever a ChangeEvent is generated by the valueHolder.
*/
private class ValueHolderChangeListener implements ChangeListener {
public void stateChanged(ChangeEvent e) {
if (!settingSelection && e instanceof ContentChangeEvent) {
if (propertyNames != null
&& listPropertyNames != null) {
// sync selection
try {
// get values from valueHolder
Object[] values = valueHolder.getPropertyValues(propertyNames);
// find match in list
int selectedItemIndex = listValueHolder.indexOf(
listPropertyNames, values);
// if found, then set selection
if (selectedItemIndex > -1) {
selectedItem = listValueHolder.get(selectedItemIndex);
} else {
if (isNullAllowed())
selectedItem = nullObject;
else
selectedItem = null;
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
fireEnableChange(
new EnableEvent(this, !((ContentChangeEvent)e).isContentNull()));
}
}
}
// =======================================================================
// ListValueHolder Properties
// =======================================================================
/**
* Set the valueHolder with the list of options for this component.
* @param newListValueHolder the valueHolder with the list of options for
* this component.
*/
public void setListValueHolder(ListValueHolder newListValueHolder) {
if (listValueHolder != null)
listValueHolder.removeChangeListener(listChangeListener);
listValueHolder = newListValueHolder;
if (listValueHolder != null)
listValueHolder.addChangeListener(listChangeListener);
}
/**
* Get the valueHolder with the list of options for this component.
* @return the valueHolder with the list of options for this component.
*/
public ListValueHolder getListValueHolder() {
return listValueHolder;
}
/**
* Set the property name in the ListValueHolder which will provide the
* selection value. This name must correspond with the propertyName for the
* valueHolder.
* @param listPropertyName the property name in the ListValueHolder which will
* provide the selection value.
*/
public void setListPropertyName(String listPropertyName) {
if (listPropertyNames == null || listPropertyNames.length < 1)
listPropertyNames = new String[] {listPropertyName};
else
listPropertyNames[0] = listPropertyName;
}
/**
* Get the property name in the ListValueHolder which will provide the
* selection value. This name must correspond with the propertyName for the
* valueHolder.
* @return the property name in the ListValueHolder which will provide the
* selection value.
*/
public String getListPropertyName() {
if (listPropertyNames == null || listPropertyNames.length < 1)
return null;
else
return listPropertyNames[0];
}
/**
* Set the property names in the ListValueHolder which will provide the
* selection values. These names must correspond with the propertyNames for
* the valueHolder.
* @param listPropertyNames the property names in the ListValueHolder which
* will provide the selection values.
*/
public void setListPropertyNames(String[] listPropertyNames) {
this.listPropertyNames = listPropertyNames;
}
/**
* Get the property names in the ListValueHolder which will provide the
* selection values. These names must correspond with the propertyNames for
* the valueHolder.
* @return the property names in the ListValueHolder which will provide the
* selection values.
*/
public String[] getListPropertyNames() {
return listPropertyNames;
}
/**
* Invoked whenever a ChangeEvent is generated by the listValueHolder.
*/
private class ListChangeListener implements ChangeListener {
public void stateChanged(ChangeEvent e) {
if (e instanceof ContentValueChangeEvent) {
fireContentsChanged(this, 0, listValueHolder.size() - 1);
} else if (e instanceof ListContentChangeEvent) {
fireContentsChanged(this, 0, listValueHolder.size() - 1);
} else if (e instanceof ContentChangeEvent) {
fireContentsChanged(this, 0, listValueHolder.size() - 1);
} else if (e instanceof StructureChangeEvent) {
fireContentsChanged(this, 0, listValueHolder.size() - 1);
}
}
}
// =======================================================================
// Null Value Properties
// =======================================================================
/**
* Sets indicator that a null value is a valid selection.
* Default is true.
*/
public void setNullAllowed(boolean nullAllowed) {
this.nullAllowed = nullAllowed;
if (nullAllowed && selectedItem == null)
selectedItem = nullObject;
else if (!nullAllowed && selectedItem instanceof NullObject)
selectedItem = null;
}
/**
* Returns indicator that a null value is a valid selection.
* Default is true.
*/
public boolean isNullAllowed() {
return nullAllowed;
}
/**
* Sets text to display in list for a null value.
*/
public void setNullDisplay(String text) {
nullObject.setText(text);
}
/**
* Returns text to display in list for a null value.
*/
public String getNullDisplay() {
return nullObject.getText();
}
// =======================================================================
// Enable Change Related Properties
// =======================================================================
/**
* Removes the given listener from the list that is notified each time the
* enabled state changes. EnableEvents are generated whenever
* the contents of the ValueHolder change. They indicate whether or not a
* component can modify the current contents of the ValueHolder (not-null).
* @param l the EnableListener to remove from the notify list.
*/
public synchronized void removeEnableListener(EnableListener l) {
if (enableListeners != null && enableListeners.contains(l)) {
Vector v = (Vector) enableListeners.clone();
v.removeElement(l);
enableListeners = v;
}
}
/**
* Adds the given listener to the list that is notified each time the
* enabled state changes. EnableEvents are generated whenever the contents
* of the ValueHolder change. They indicate whether or not a component
* can modify the current contents of the ValueHolder (not-null).
* @param l the EnableListener to add to the notify list.
*/
public synchronized void addEnableListener(EnableListener l) {
Vector v = enableListeners == null ? new Vector(2) : (Vector) enableListeners.clone();
if (!v.contains(l)) {
v.addElement(l);
enableListeners = v;
}
}
/**
* Notify the listeners that the enabled state has changed. EnableEvents are
* generated whenever the contents of the ValueHolder change. They indicate
* whether or not a component can modify the current contents of the
* ValueHolder (not-null).
* @param e the EnableEvent to send to the listeners on the notify list.
*/
protected void fireEnableChange(EnableEvent e) {
if (enableListeners != null) {
Vector listeners = enableListeners;
int count = listeners.size();
for (int i = 0; i < count; i++) {
((EnableListener) listeners.elementAt(i)).enableChange(e);
}
}
}
/**
* Get indicator whether or not the the property value of the ValueHolder
* can be changed. A VO type ValueHolder can only be changed if its object
* is not null. A Collection type ValueHolder can only be changes if it is
* not empty.
*/
private boolean isChangeable() {
if (valueHolder == null)
return false;
if (valueHolder instanceof VOValueHolder) {
return ((VOValueHolder)valueHolder).getObject() != null;
} else if (valueHolder instanceof CollectionValueHolder) {
if (((CollectionValueHolder)valueHolder).isEmpty())
return false;
else if (valueHolder instanceof VOCollectionValueHolder ||
valueHolder instanceof VOListValueHolder)
return ((CollectionValueHolder)valueHolder).getObject() != null;
else
return true;
} else {
return true;
}
}
}